package com.sq.util;

import com.sq.util.exception.VisualException;

/**
 * @author sq
 *
 */
public class ByteUtil {

    public static String toBinaryString(byte[] arr) {
        StringBuffer sb = new StringBuffer(arr.length * 8);
        for (byte b : arr) {
            sb.append(toBinaryString(b));
        }
        return sb.toString();
    }

    public static String toBinaryString(byte b) {
        String s = "00000000" + Integer.toBinaryString(b);
        return s.substring(s.length() - 8);
    }

    public static String shiftLeft(byte[] arr, int num) {
        StringBuffer sb = new StringBuffer(arr.length * 8 + num);
        sb.append(toBinaryString(arr));
        for (int i = 0; i < num; i++) {
            sb.append('0');
        }
        return sb.toString().substring(num);
    }

    public static String shiftLeft(String binaryString, int num) {
        StringBuffer sb = new StringBuffer(binaryString.length() + num);
        sb.append(binaryString);
        for (int i = 0; i < num; i++) {
            sb.append('0');
        }
        return sb.toString().substring(num);
    }

    // 补全多少位
    public static String completing(String binaryString, int num) {
        int length = binaryString.length();
        VisualException.isTrue(length <= num, "位数不对");
        int j = num - length;
        StringBuffer sb = new StringBuffer(j);
        for (int i = 0; i < j; i++) {
            sb.append('0');
        }
        sb.append(binaryString);
        return sb.toString();
    }

    public static byte cycleLeft(byte b, int num) {
        VisualException.isTrue(num < 8, "不能超过8");
        return (byte) ((b & 0xFF) << num | (b & 0xFF) >> (8 - num));
    }

    public static byte cycleRight(byte b, int num) {
        VisualException.isTrue(num < 8, "不能超过8");
        return (byte) ((b & 0xFF) >> num | (b & 0xFF) << (8 - num));
    }

    public static byte[] binaryStringToBytes(String str) {
        VisualException.isTrue(str.length() % 8 == 0, "字符串长度不符");
        int length = str.length() / 8;
        byte[] result = new byte[length];
        char[] chars = str.toCharArray();
        for (int i = 0; i < length; i++) {
            int start = i * 8;
            int num = 0;
            for (int j = 0; j < 8; j++) {
                char c = chars[start + j];
                if (c == '1') {
                    num = 1 << (7 - j) | num;
                } else if (c != '0') {
                    throw new VisualException("字符" + c + "非法");
                }
            }
            result[i] = (byte) num;
        }
        return result;
    }

    public static boolean isEqual(byte[] arr1, byte[] arr2) {
        if (arr1.length != arr2.length) {
            return false;
        }
        for (int i = 0; i < arr1.length; i++) {
            if (arr1[i] != arr2[i]) {
                return false;
            }
        }
        return true;
    }

    public static byte[] toBytes(String hexString) {
        if (hexString == null || hexString.equals("")) {
            return null;
        }
        hexString = hexString.toUpperCase();
        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] result = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2;
            result[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
        }
        return result;
    }

    public static String toHexString(byte[] src) {
        return toHexString(src, 0, src.length);
    }

    public static String toHexString(byte[] src, int start, int end) {
        StringBuilder stringBuilder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = start; i < end; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    public static byte[] reverse(byte[] arr) {
        int i = 0, j = arr.length - 1;
        for (; i < j; i++, j--) {
            byte b = arr[i];
            arr[i] = arr[j];
            arr[j] = b;
        }
        return arr;
    }

    // 十六进制 与 int 的相互转换
    public static int toInt(String hexString) {
        return toInt(toBytes(hexString));
    }

    public static String toHexString(int n) {
        String hexString = toHexString(intToBytes(n));
        for (int i = 0; i < 3; i++) {
            hexString = hexString.replaceFirst("00", "");
        }
        return hexString;
    }

    // byte 数组与 int 的相互转换
    public static int toInt(byte[] arr) {
        int length = arr.length;
        int n = length - 1;
        int a = (arr[n] & 0xFF);
        for (int j = 1; j < length; j++) {
            a = a | (arr[n - j] & 0xFF) << (8 * j);
        }
        return a;
    }

    public static byte[] intToBytes(int i) {
        int length = 4;
        byte[] arr = new byte[length];
        for (int j = 0; j < length; j++) {
            int k = 24 - 8 * j;
            arr[j] = (byte) ((i >> k) & 0xFF);
        }
        return arr;
    }

    public static byte[] shortToBytes(short i) {
        int length = 2;
        byte[] arr = new byte[length];
        for (int j = 0; j < length; j++) {
            int k = 8 - 8 * j;
            arr[j] = (byte) ((i >> k) & 0xFF);
        }
        return arr;
    }

    // byte 数组与 long 的相互转换
    public static byte[] longToBytes(long l) {
        int length = 8;
        byte[] arr = new byte[length];
        for (int j = 0; j < length; j++) {
            int k = 56 - 8 * j;
            arr[j] = (byte) ((l >> k) & 0xFF);
        }
        return arr;
    }

    public static long toLong(byte[] arr) {
        return toLong(arr, 0, arr.length);
    }

    public static long toLong(byte[] arr, int start, int end) {
        long a = 0;
        for (int j = start; j < end; j++) {
            a = a | (((long) (arr[end - 1 - j])) & 0xFF) << (8 * j);
        }
        return a;
    }

    private static byte charToByte(char c) {
        return (byte) "0123456789ABCDEF".indexOf(c);
    }

}
